package com.sky.service.impl;

import com.sky.dto.SalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrderDetailMapper;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;

/**
 * @author 老杨
 * @version 1.0
 */
@Service
@Slf4j
public class ReportServiceImpl implements ReportService {

    @Autowired
    OrderMapper orderMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    OrderDetailMapper detailMapper;

    @Autowired
    WorkspaceService workspaceService;


    @Override
    public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
        //返回 时间区间 中每一天的 营业额

//        当天营业额 == 当天所有订单 实收金额之和 ，且排除 取消状态的订单
        //把 当天日期 和 当天 营业额按顺序 拼接到 两个字符串中
        TurnoverReportVO turnoverReportVO = new TurnoverReportVO();

        //先把 时间区间中 按天形式 全部保存到集合中，然后 把集合中元素 转为字符串，用逗号分隔

        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while (!begin.equals(end)){
            begin = begin.plusDays(1); //加1 ，重新赋值
            dateList.add(begin);
        }
        //转为字符串，用逗号分隔
        String join = StringUtils.join(dateList,",");
        //放到 vo中
        turnoverReportVO.setDateList(join);

        //计算当天的营业额
        HashMap map = new HashMap<>();
        List turnoverList = new ArrayList();
        for(LocalDate localDate : dateList){
            //计算当天 0点 到 23：59：59 之间的订单营业额
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            map.put("begin",beginTime);
            map.put("end",endTime);
            map.put("status", Orders.COMPLETED);
            Double aDouble = orderMapper.sumAmount(map);
           aDouble = aDouble == null?0.0:aDouble;
            turnoverList.add(aDouble);
        }
        String join1 = StringUtils.join(turnoverList, ",");
        turnoverReportVO.setTurnoverList(join1);


        return turnoverReportVO;
    }

    @Override
    public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = dateList(begin, end);
        //转为字符串，用逗号分隔
        String dateListSting = StringUtils.join(dateList,",");

        //每天新增用户量
        HashMap map = new HashMap();
        ArrayList newUserList = new ArrayList();
        ArrayList totalUserList = new ArrayList();
        for(LocalDate localDate : dateList){
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            map.put("begin",beginTime);
            map.put("end",endTime);
            Integer integer = userMapper.peopleNum(map);
            integer = integer == null?0:integer;
            newUserList.add(integer);

            //获取一天结束前 之前的所有用户
            Integer total = userMapper.totalNum(map);
            totalUserList.add(total);
        }
        //每天的新增用户 字符串
        String newUserListString = StringUtils.join(newUserList, ",");
        String totalUserListString = StringUtils.join(totalUserList, ",");

        UserReportVO userReportVO = new UserReportVO();
        userReportVO.setDateList(dateListSting);
        userReportVO.setNewUserList(newUserListString);
        userReportVO.setTotalUserList(totalUserListString);

        return userReportVO;
    }

    @Override
    public OrderReportVO ordersStatistics(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = dateList(begin, end);
        String dateListString = StringUtils.join(dateList,",");
        //每日订单数
        ArrayList<Integer> orderNumsList = new ArrayList();
        ArrayList<Integer> effectiveOrderNumsList = new ArrayList();
        for (LocalDate localDate : dateList){
            HashMap map = new HashMap();
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            map.put("end",endTime);
            map.put("begin",beginTime);
            //当天总订单数
            Integer orderNums = orderMapper.orderNums(map);
            orderNumsList.add(orderNums);
            //当天有效订单数
            map.put("status",Orders.COMPLETED);
           Integer effectiveOrderNums = orderMapper.orderNums(map);
            effectiveOrderNumsList.add(effectiveOrderNums);
        }

        //每日订单数
        String orderNumsListStr = StringUtils.join(orderNumsList, ",");
        //当天有效订单数
        String effectiveOrderNumsListStr = StringUtils.join(effectiveOrderNumsList, ",");
        //订单总数   --- 区间内 的总订单数
//                累加 每天订单数集合
        Integer orderTotal = orderNumsList.stream().reduce(Integer::sum).get();
        //有效订单总数
//              累加 有效订单集合
        Integer validOrderNum = effectiveOrderNumsList.stream().reduce(Integer::sum).get();

        //订单完成率
        int v = validOrderNum;
        int o =orderTotal;
        Double compRate = (double)v / (double)o;

        //封装数据
        OrderReportVO orderReportVO = new OrderReportVO();
        orderReportVO.setDateList(dateListString);
        orderReportVO.setOrderCountList(orderNumsListStr);
        orderReportVO.setValidOrderCountList(effectiveOrderNumsListStr);
        orderReportVO.setTotalOrderCount(orderTotal);
        orderReportVO.setValidOrderCount(validOrderNum);
        orderReportVO.setOrderCompletionRate(compRate);//订单完成率

        return orderReportVO;
    }

    @Override
    public SalesTop10ReportVO top10(LocalDate begin, LocalDate end) {
        //思路分析：
//        1.使用多表查询
//        2.查询 订单详情表的菜品和套餐，且和订单表一起查询，只保留 订单成功的的订单详情表
//        2.且 在一定时间区间的数据
//        3.根据 名字分组查询，然后 记录每组数量 ，然后排序 降序
//        4.最后只截取 前10条记录
//        sql 语句：SELECT count(order_detail.id) as num ,`name` from order_detail ,(SELECT * from orders where status = 5) as ods
//				where order_detail.order_id = ods.id  and ods.order_time > '2022-10-11 00:00:00' and ods.order_time< '2024-10-17 00:00:00'
//						GROUP BY `name`
//								ORDER BY num DESC
//								LIMIT 10
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
        Map map = new HashMap();
        map.put("begin",beginTime);
        map.put("end",endTime);
        map.put("status",Orders.COMPLETED);
        List<SalesDTO> salesDTOS = detailMapper.top10(map);
        log.info("拿到的top10 数据 {}",salesDTOS);
        //拿到 top 10 的商品 和数量后 ，在遍历出来 各自保存到 另一个集合中
        ArrayList<String> nameList = new ArrayList<>();
        ArrayList<Integer> numberList = new ArrayList<>();
        for (SalesDTO salesDTO : salesDTOS){
            nameList.add(salesDTO.getName());
            numberList.add(salesDTO.getNum());
        }
        String nameListStr = StringUtils.join(nameList, ",");
        String numberListStr = StringUtils.join(numberList,",");
        SalesTop10ReportVO salesTop10ReportVO = new SalesTop10ReportVO();
        salesTop10ReportVO.setNameList(nameListStr);
        salesTop10ReportVO.setNumberList(numberListStr);

        return salesTop10ReportVO;
    }

    @Override
    public void export(HttpServletResponse httpServletResponse) {
        //获得数据库数据
//            获取 前30天 和 昨天 区间的日期
        LocalDate begin = LocalDate.now().minusDays(30);
        LocalDate end = LocalDate.now().minusDays(1);

        LocalDateTime of = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime of2 = LocalDateTime.of(end, LocalTime.MAX);
//        30 天的总数据
        BusinessDataVO businessData = workspaceService.getBusinessData(of, of2);



//        将数据 放到excel 表格中
//            读取现有的 excel模板文件，再次基础上添加数据
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("file/运营数据报表模板.xlsx");
        try {
            //绑定 模板
            XSSFWorkbook excel = new XSSFWorkbook(inputStream);
            //拿到 sheet页
            XSSFSheet sheetAt = excel.getSheetAt(0);
            //添加概括数据
            sheetAt.getRow(1).getCell(1).setCellValue("时间："+begin+"\t至"+end);
            XSSFRow row3 = sheetAt.getRow(3);
            row3.getCell(2).setCellValue(businessData.getTurnover());
            row3.getCell(4).setCellValue(businessData.getOrderCompletionRate());
            row3.getCell(6).setCellValue(businessData.getNewUsers());

            XSSFRow row4 = sheetAt.getRow(4);
            row4.getCell(2).setCellValue(businessData.getValidOrderCount());
            row4.getCell(4).setCellValue(businessData.getUnitPrice());


            //添加 详情数据 -- 把30天，每天的数据都输出
            for (int i = 0; i < 30; i++) {
//                拿到 某一天日期
                LocalDate data = begin.plusDays(i);
                LocalDateTime beginTime = LocalDateTime.of(data, LocalTime.MIN);
                LocalDateTime endTime = LocalDateTime.of(data, LocalTime.MAX);
                //获得 某一天数据
                BusinessDataVO businessData1 = workspaceService.getBusinessData(beginTime, endTime);

                XSSFRow row = sheetAt.getRow(7 + i);
                row.getCell(1).setCellValue(data.toString());
                row.getCell(2).setCellValue(businessData1.getTurnover());
                row.getCell(3).setCellValue(businessData1.getValidOrderCount());
                row.getCell(4).setCellValue(businessData1.getOrderCompletionRate());
                row.getCell(5).setCellValue(businessData1.getUnitPrice());
                row.getCell(6).setCellValue(businessData1.getNewUsers());

            }




            //将表格 输出到 客户端浏览器上
            ServletOutputStream outputStream = httpServletResponse.getOutputStream();
            excel.write(outputStream);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    //封装方法，返回 日期区间集合
    public List<LocalDate> dateList(LocalDate begin,LocalDate end){
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);
        while (!begin.equals(end)){
            begin = begin.plusDays(1); //加1 ，重新赋值
            dateList.add(begin);
        }
        return dateList;
    }
}
